//------------------------------------------------------------------------------
//
//   author: 小兵（aosnow@yeah.net）
//   create: 2012-5-26 下午12:14:26
//    class: HttpRequest - Http网络服务请求，一般连接请求的URL是一个php、jsp、aspx
//						        等动态文件地址
//
//------------------------------------------------------------------------------

package starfire.rpc.http
{

	import starfire.events.ServiceEvent;
	import starfire.namespaces.sn_internal;
	import starfire.utils.strings.json;

	import flash.events.TimerEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLVariables;
	import flash.utils.Timer;

	use namespace sn_internal;

	public class HttpLoader extends URLLoader
	{
		//--------------------------------------------------------------------------
		//
		//  Class constants
		//
		//--------------------------------------------------------------------------

		public static const REQUEST_TIMEOUT:String = "REQUEST_TIMEOUT";

		//--------------------------------------------------------------------------
		//
		//  Class constructor
		//
		//--------------------------------------------------------------------------

		public function HttpLoader( message:HttpRequestMessage = null )
		{
			_request = new URLRequest();
			_message = message;

			if( _message == null )
			{
				_message = new HttpRequestMessage;
				_message.contentType = HttpRequestMessage.CONTENT_TYPE_FORM;
				_message.method = HttpRequestMessage.METHOD_POST;
				_message.timeOut = 30; // 默认30秒超时
			}
		}

		//--------------------------------------------------------------------------
		//
		//	Class properties
		//
		//--------------------------------------------------------------------------

		sn_internal var _message:HttpRequestMessage;
		private var _request:URLRequest;
		private var _resultFormat:String;

		private var _parseData:*;

		//--------------------------------------------------------------------------
		//
		//	Class methods
		//
		//--------------------------------------------------------------------------

		override public function load( request:URLRequest ):void
		{
			send( request.data );
		}

		/** 取得服务成功返回收到的数据  **/
		public function get result():*
		{
			if( _parseData == null )
				_parseData = HttpResult.processResult( super.data, resultFormat );
			return _parseData;
		}

		/**
		 * 设置请求服务时需要发送的数据
		 * @param value						- 发送数据
		 */
		public function set dataRequest( value:Object ):void
		{
			_message.data = value;
		}

		public function get dataRequest():Object
		{
			return _message.data;
		}

		/**
		 * 请求服务的超时时间（单位：秒，超时后将自动结束请求）
		 * @param value					- 超时时间（单位：秒）
		 */
		public function set timeOut( value:uint ):void
		{
			if( value > 0 )
				_message.timeOut = value;
		}

		public function get timeOut():uint
		{
			return _message.timeOut;
		}

		public function set url( value:String ):void
		{
			_message.url = value;
		}

		public function get url():String
		{
			return _message.url;
		}

		/**
		 * data 属性中内容的 MIME 内容类型。
		 * <p>默认值为 application/x-www-form-urlencoded。</p>
		 * <p><strong>注意：</strong>FileReference.upload()、FileReference.download() 和 HTMLLoader.load() 方法不支持 URLRequest.contentType 属性。</p>
		 * <p>发送 POST 请求时，contentType 和 data 属性的值必须正确对应。contentType 属性的值表示服务器如何解释 data 属性的值。 </p>
		 * <UL>
		 *   <li>如果 data 属性的值是一个 URLVariables 对象，则 contentType 的值必须是 application/x-www-form-urlencoded。</li>
		 *   <li>如果 data 属性的值为其他类型，则 contentType 的值应表示将要发送的 POST 数据的类型（该数据为 data 属性的值中包含的二进制或字符串数据）。</li>
		 *   <li>对于 FileReference.upload()，请求的内容类型将自动设置为   multipart/form-data 并忽略 contentType 属性的值。</li>
		 * </UL>
		 * <p>在 Flash Player 10 和更高版本中，如果使用包含上载（由 POST 体内的“content-disposition”标头中的“filename”参数表示）的 multipart Content-Type（例如 “multipart/form-data”），则 POST 操作会受应用于上载的安全规则的约束：</p>
		 * <UL>
		 *   <li>必须执行 POST 操作以响应用户启动的操作（如鼠标单击或按键）。</li>
		 *   <li>如果 POST 操作是跨域的（POST 目标与发送 POST 请求的 SWF 文件不在同一台服务器上），则目标服务器必须提供一个允许跨域访问的 URL 策略文件。</li>
		 * </UL>
		 * <p>另外，对于任何 multipart Content-Type，语法必须有效（根据 RFC2046 标准）。如果语法无效，则 POST 操作受应用于上载的安全规则约束。</p>
		 */
		public function set contentType( value:String ):void
		{
			_message.contentType = value;
		}

		public function get contentType():String
		{
			return _message.contentType;
		}

		/**
		 * 发送请求时的请求类型，参数必须为以下两者之一：
		 * <code>
		 * <li>HttpRequestMessage.GET</li>
		 * <li>HttpRequestMessage.POST</li>
		 * </code>
		 */
		public function set method( value:String ):void
		{
			_message.method = value;
		}

		public function get method():String
		{
			return _message.method;
		}

		public function get resultFormat():String
		{
			return _resultFormat;
		}

		/**
		 * <p>指示如何反序列化由 HTTP 调用返回的结果的值。该项目的值根据以下条件确定：</p>
		 * <ul>
		 * <li>返回的是 XML 还是名称/值对。</li>
		 * <li>访问结果的方式；可以将结果作为 object、text 或 XML 进行访问。</li>
		 * </ul>
		 * <p>默认值为 object。允许使用的值包括：</p>
		 *
		 * <ul>
		 * <li>RESULT_FORMAT_FLASHVARS：返回的值是包含由 &amp; 符号分隔的名称=值对的文本，该文本被分析为 Object</li>
		 * <li>RESULT_FORMAT_JSON：返回的值是 JSON 格式文本，并且按照 Object 对象树分析。</li>
		 * <li>RESULT_FORMAT_OBJECT（默认值）：返回的值为 {name:value} 格式文本，并且按照 Object 对象树分析，与返回值结构相同。
		 * 值的结构中，可以包含 {} 结构嵌套，但数据值只能为基本数据类型（数值、字符串、布尔值、NaN、Null）。要使用复杂数据类型，
		 * 请改用 JSON 格式数据返回。</li>
		 * <li>RESULT_FORMAT_TEXT：返回的值为文本并且未经处理。文本形式的原始内容。</li>
		 * <li>RESULT_FORMAT_XML：返回的值为 XML 格式文本，并且自动转换为  XML 对象返回</li>
		 * </ul>
		 */
		public function set resultFormat( value:String ):void
		{
			_resultFormat = value;
		}

		//--------------------------------------------------------------------------
		//
		//   服务请求超时处理
		//
		//--------------------------------------------------------------------------

		private var _requestTimer:Timer;
		private var _requestTimedOut:Boolean;

		public function get requestTimedOut():Boolean
		{
			return _requestTimedOut;
		}

		protected function startRequestTimeout( requestTimeout:int ):void
		{
			_requestTimer = new Timer( requestTimeout * 1000, 1 );
			_requestTimer.addEventListener( TimerEvent.TIMER_COMPLETE, timeoutRequest );
			_requestTimer.start();
		}

		public function releaseTimer():void
		{
			_requestTimedOut = false;
			_requestTimer.stop();
			_requestTimer.removeEventListener( TimerEvent.TIMER_COMPLETE, timeoutRequest );
			_requestTimer = null;
		}

		private function timeoutRequest( event:TimerEvent ):void
		{
			_requestTimedOut = true;
			releaseTimer();
			close();

			var timeEvent:ServiceEvent = new ServiceEvent( REQUEST_TIMEOUT );
			timeEvent.setTimeout( _requestTimedOut );
			dispatchEvent( timeEvent );

			// 将 Http 信息配置对象置为就绪状态 
			_message.sn_internal::setInactive( true );
		}

		//--------------------------------------------------------------------------
		//
		//   服务请求发送
		//
		//--------------------------------------------------------------------------

		/**
		 * 立即发送 HTTP 服务请求，这是根据所设置的 <code>HttpRequestMessage</code> 信息来请的
		 * @param dataRequest 系统将始终优先发送这个数据，若设置了数据则会忽略
		 * <code>HttpRequestMessage</code> 的 <code>data</code> 数据。
		 * 默认为 <code>null</code>，若保持这个值，才会尝试发送
		 * <code>HttpRequestMessage</code> 的 <code>data</code> 数据，若无数据，则不会发送任何数据。
		 */
		public function send( dataRequest:Object = null ):void
		{
			if( _message )
			{
				_request.url = _message.url;
				_request.contentType = _message.contentType;
				_request.method = _message.method.toUpperCase();

				var sendData:Object = dataRequest != null ? dataRequest : _message.data;

				if( sendData != null )
				{
					switch( _message.contentType )
					{
						case HttpRequestMessage.CONTENT_TYPE_XML:
						case HttpRequestMessage.CONTENT_TYPE_SOAP_XML:
						{
							if( sendData is XML )
							{
								sendData = sendData.toXMLString();
							}
							else if( sendData is XMLList )
							{
								var xml:XML = <root></root>;

								for each( var child:XML in sendData.elements())
									xml.appendChild( child );

								sendData = xml.toXMLString();
								xml = null;
							}

							_request.data = sendData;
							break;
						}
						case HttpRequestMessage.CONTENT_TYPE_JSON:
						{
							_request.data = json( sendData );
							break;
						}
						default:
						{
							if( sendData || _message.keyData )
							{
								var variables:URLVariables;
								var isTrueVariables:Boolean;

								// 格式化提交数据
								if( sendData )
								{
									if( sendData is URLVariables )
									{
										variables = sendData as URLVariables;
										isTrueVariables = variables != null;
									}
									else
									{
										variables = new URLVariables();

										for( var p:String in sendData )
										{
											variables[ p ] = sendData[ p ];
											isTrueVariables = true;
										}
									}
								}

								// 添加附加验证数据
								if( _message.keyData )
								{
									variables = variables || new URLVariables();

									for( var k:String in _message.keyData )
									{
										variables[ k ] = _message.keyData[ k ];
										isTrueVariables = true;
									}
								}

								_request.data = isTrueVariables ? variables : null;
							}
						}
					}
				}
				else
				{
					_request.data = null;
				}

				if( _request.contentType == HttpRequestMessage.CONTENT_TYPE_XML && _request.method == HttpRequestMessage.METHOD_GET )
					_request.method = HttpRequestMessage.METHOD_POST;

				if( _request.method == HttpRequestMessage.METHOD_POST && _message.httpHeaders && _message.httpHeaders.length > 0 )
				{
					var array:Array = [];

					for each( var h:URLRequestHeader in _message.httpHeaders )
					{
						array.push( h );
					}

					_request.requestHeaders = array;
				}

				super.load( _request );

				_requestTimedOut = false;
				startRequestTimeout(( _message.timeOut > 0 ? _message.timeOut : 30 ) * 1000 );
			}
		}
	}
}
